﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using NUnit.Framework;
using Studio7i.Persistencia.ADO;
using Studio7i.Dominio;
using Studio7i.Persistencia;
using Studio7i.Persistencia.NH;

namespace Studio7i.Pruebas
{
    [TestFixture]
    public class Test2_SalaDAO
    {
        // DAOs a utilizar durante las pruebas
        private ILocalDAO localDAO = null;
        private IInstrumentoDAO instrumentoDAO = null;
        private ISalaDAO salaDAO = null;
        // Variables de soporte para las pruebas
        private Local local1 = null;
        private Local local2 = null;
        private Instrumento instrumento1 = null;
        private Instrumento instrumento2 = null;
        private int codigoSala = 0;

        [TestFixtureSetUp]
        public void PrepararPruebas()
        {
            // 1. Definimos la implementación de DAO a probar (ADO / NH / EF)
            localDAO = new Persistencia.EF.LocalDAO();
            instrumentoDAO = new Persistencia.EF.InstrumentoDAO();
            salaDAO = new Persistencia.EF.SalaDAO();
            // 2. Eliminamos todas las salas en BD antes de las pruebas
            foreach (Sala sala in salaDAO.ListarTodos())
                salaDAO.Eliminar(sala);
            // 3. Creamos objetos dependientes necesarios
            local1 = localDAO.Crear(new Local() { Nombre = "C41", Direccion = "Monterrico" });
            local2 = localDAO.Crear(new Local() { Nombre = "F31", Direccion = "San Miguel" });
            instrumento1 = instrumentoDAO.Crear(new Instrumento()
            {
                Tipo = "Guitarra", Marca = "Fender", Modelo = "Squier",
                AnhoFabricacion = 2010, Caracteristicas = "Blanca", CostoAlquiler = 20
            });
            instrumento2 = instrumentoDAO.Crear(new Instrumento()
            {
                Tipo = "Guitarra", Marca = "Fender", Modelo = "Stratocaster",
                AnhoFabricacion = 2011, Caracteristicas = "Morada", CostoAlquiler = 15
            });
        }
        [Test]
        public void Test1_Crear()
        {
            // 1. Clase a probar: SalaDAO
            Assert.IsNotNull(salaDAO);
            // 2. Declaramos e instanciamos la entidad de dominio
            Sala salaACrear = new Sala()
            {
                Nombre = "Elvis Lives!", Caracteristicas = "Memphis", Capacidad = 400,
                Local = local1, Comentarios = "5mentarios",
                Instrumentos = new List<Instrumento>() { instrumento1, instrumento2 }
            };
            // 3. Declaramos la entidad que contendrá el resultado
            Sala salaCreada = null;
            // 4. Probamos que no ocurra error al ejecutar el método
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salaCreada = salaDAO.Crear(salaACrear);
                codigoSala = salaCreada.Codigo;
            });
            // Probamos que la entidad resultante no sea nula
            Assert.IsNotNull(salaCreada);
            // Probamos que el código generado sea mayor a 0
            Assert.Greater(salaCreada.Codigo, 0);
            // Probamos que el nombre registrado es igual al solicitado con la entidad
            Assert.AreEqual(salaCreada.Nombre, salaACrear.Nombre);
            // Probamos que la característica registrada es igual a la solicitada con la entidad
            Assert.AreEqual(salaCreada.Caracteristicas, salaACrear.Caracteristicas);
            // Probamos que la asociación con los 2 instrumentos se haya guardado
            Assert.AreEqual(salaCreada.Instrumentos.Count, 2);
        }
        [Test]
        public void Test2_Obtener()
        {
            // 1. Clase a probar: LocalDAO
            Assert.IsNotNull(salaDAO);
            // 2. Definimos los datos para la prueba
            int codigo = codigoSala;
            // 3. Declaramos la entidad que contendrá el resultado
            Sala salaObtenida = null;
            // 4. Probamos que no ocurra error al ejecutar el método
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salaObtenida = salaDAO.Obtener(codigo);
            });
            // Probamos que la entidad resultante no sea nula
            Assert.IsNotNull(salaObtenida);
            Assert.AreEqual(salaObtenida.Codigo, codigo);
            Assert.IsNotNullOrEmpty(salaObtenida.Nombre);
            Assert.IsNotNullOrEmpty(salaObtenida.Caracteristicas);
            Assert.AreEqual(salaObtenida.Instrumentos.Count, 2);
        }
        [Test]
        public void Test3_Modificar()
        {
            // 1. Clase a probar: LocalDAO
            Assert.IsNotNull(salaDAO);
            // 2. Declaramos e instanciamos la entidad de dominio
            Sala salaAModificar = salaDAO.Obtener(codigoSala);
            // a. Solicitamos cambios en las propiedades escalares
            salaAModificar.Nombre = "Elvis Lived!";
            salaAModificar.Caracteristicas = "Old Fashion";
            // b. Solicitamos cambios en un objeto anidado
            salaAModificar.Local = local2;
            // c. Solicitamos un cambio en la composición de la colección many-to-many
            salaAModificar.Instrumentos.Remove(salaAModificar.Instrumentos.Single(i => i.Codigo == instrumento1.Codigo));
            // 3. Declaramos la entidad que contendrá el resultado
            Sala salaModificada = null;
            // 4. Probamos que no ocurra error al ejecutar el método
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salaModificada = salaDAO.Modificar(salaAModificar);
            });
            // Probamos que la entidad resultante no sea nula
            Assert.IsNotNull(salaModificada);
            // Probamos que el código generado sea mayor a 0
            Assert.AreEqual(salaModificada.Codigo, codigoSala);
            // Probamos que el nombre registrado es igual al solicitado con la entidad
            Assert.AreEqual(salaModificada.Nombre, salaAModificar.Nombre);
            // Probamos que la característica registrada es igual a la solicitada con la entidad
            Assert.AreEqual(salaModificada.Caracteristicas, salaAModificar.Caracteristicas);
            // Probamos que ahora sólo tenga asociado 1 instrumento
            Assert.AreEqual(salaModificada.Instrumentos.Count, 1);
        }
        [Test]
        public void Test4_Eliminar()
        {
            // 1. Clase a probar: LocalDAO
            Assert.IsNotNull(salaDAO);
            // 2. Definimos la entidad que contendrá el resultado
            Sala salaExistente = salaDAO.Obtener(codigoSala);
            // 3. Probamos que no ocurra error al ejecutar el método
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salaDAO.Eliminar(salaExistente);
            });
            // Probamos que la entidad ya no existe
            Assert.IsNull(salaDAO.Obtener(codigoSala));
        }
        [Test]
        public void Test5_ListarTodos()
        {
            // 1. Clase a probar: LocalDAO
            Assert.IsNotNull(salaDAO);
            // 2. Declaramos la entidad que contendrá el resultado
            ICollection<Sala> salasEncontradas = null;
            // 3. Probamos que no ocurra error al ejecutar el método
            salaDAO.Crear(new Sala() { Nombre = "Rock 80s", Caracteristicas = "Premium", Capacidad = 8, Local = local1, Comentarios = "Zzz..." });
            salaDAO.Crear(new Sala() { Nombre = "Electrónico 90s", Caracteristicas = "VIP", Capacidad = 6, Local = local2 });
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salasEncontradas = salaDAO.ListarTodos();
            });
            // Probamos que la entidad resultante no sea nula
            Assert.IsNotNull(salasEncontradas);
            // Probamos que la cantidad de locales encontrados sea 2
            Assert.AreEqual(salasEncontradas.Count, 2);
            // Probamos que cada local contenga la cadena de búsqueda en su nombre
            foreach (Sala salaEncontrada in salasEncontradas)
            {
                Assert.IsNotNull(salaEncontrada);
                Assert.IsInstanceOf(typeof(Sala), salaEncontrada);
            }
        }
        [Test]
        public void Test6_ListarXBusqueda()
        {
            // 1. Clase a probar: LocalDAO
            Assert.IsNotNull(salaDAO);
            // 2. Definimos los datos para la prueba
            string nombre = "ock"; // Rock *
            // 3. Declaramos la entidad que contendrá el resultado
            ICollection<Sala> salasEncontradas = null;
            // 4. Probamos que no ocurra error al ejecutar el método
            Assert.DoesNotThrow(delegate
            {
                // 5. Ejecutamos el método a probar
                salasEncontradas = salaDAO.ListarXBusqueda(null, nombre, null, null, null, null);
            });
            // Probamos que la entidad resultante no sea nula
            Assert.IsNotNull(salasEncontradas);
            // Probamos que la cantidad de locales encontrados sea 2
            Assert.AreEqual(salasEncontradas.Count, 1);
            // Probamos que cada local contenga la cadena de búsqueda en su nombre
            foreach (Sala salaEncontrada in salasEncontradas)
            {
                Assert.IsTrue(salaEncontrada.Nombre.Contains(nombre));
            }
        }
        [TestFixtureTearDown]
        public void TerminarPruebas()
        {
            foreach (Sala sala in salaDAO.ListarTodos())
                salaDAO.Eliminar(sala);
            instrumentoDAO.Eliminar(instrumento2);
            instrumentoDAO.Eliminar(instrumento1);
            localDAO.Eliminar(local2);
            localDAO.Eliminar(local1);
            NHibernateHelper.CerrarFabrica();
        }
    }
}